package com.example.demo;
import com.domain.AiPortAnswerList;
import com.domain.Answer;
import com.domain.TureList;
import com.example.demo.base.ResultEntity;
import com.mapper.AnswerMapper;
import com.openai.models.chat.completions.ChatCompletion;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

@SpringBootApplication
@RestController
@MapperScan("com.mapper")
@CrossOrigin(origins = "*")
public class DemoApplication {
	@Autowired
	ChatClient.Builder chatClientBuilder;

	@Autowired
	private RedisTemplate redisTemplate;

	@Autowired
	AnswerMapper answerMapper;



	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);

	}

	@PostMapping("/upload")
	public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile multipartFile) {


		// 基础校验
		if (multipartFile.isEmpty()) {
			return null;
		}
		System.out.println("测试数据库");
		Answer answer =new Answer();
		answer.setId(333L);
		answer.setContent("测试数据库");
		answer.setQuestionId(333L);
		answer.setIsCorrect((byte) 1);
		answerMapper.insert(answer);

		System.out.println("测试数据库");
		redisTemplate.opsForValue().set(1, "Hello Redis");
		System.out.println("连接成功！测试值: " + redisTemplate.opsForValue().get(1));

		String tikaServerUrl = "http://127.0.0.1:9999/tika"; // 注意端口改为9998

		// 使用更精准的配置
		try (CloseableHttpClient httpClient = HttpClients.createDefault();
			 InputStream fileStream = multipartFile.getInputStream()) {

			// 1. 使用 PUT 方法（与官方curl一致）
			HttpPut httpPut = new HttpPut(tikaServerUrl);

			// 2. 设置官方要求的请求头
			httpPut.setHeader("Content-Type", "application/octet-stream");
			httpPut.setHeader("Accept", "text/plain");

			// 3. 直接传输二进制流（不使用multipart）
			httpPut.setEntity(new InputStreamEntity(fileStream, multipartFile.getSize(),
					ContentType.APPLICATION_OCTET_STREAM));

			// 4. 执行请求
			try (CloseableHttpResponse response = httpClient.execute(httpPut)) {
				int statusCode = response.getStatusLine().getStatusCode();

				if (statusCode == 200) {
					String result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);

					// 控制台输出（调试用）
					System.out.println("========== 解析结果 ==========");
					System.out.println(result);
					//异步调取，并且传入时间戳
					// 异步调用 qryAliFlux 方法并传入时间戳
					long timestamp = System.currentTimeMillis();
					 CompletableFuture.runAsync(() -> {
                         try {
                             qryAliFlux(result, timestamp);
                         } catch (InterruptedException e) {
                             throw new RuntimeException(e);
                         }
                     });

					 //qi

					System.out.println("============================");

					// ... 你的处理逻辑 ...
					String id = String.valueOf(timestamp);
					return ResponseEntity.ok()
							.contentType(MediaType.TEXT_PLAIN)
							.body(id);
				} else {
					String errorMsg = "Tika解析失败，状态码: " + statusCode;
					System.err.println(errorMsg);
					return null;
				}
			}
		} catch (Exception e) {
			System.err.println("调用Tika服务异常:");
			e.printStackTrace();
			return null;
		}
	}


	public TureList qryAliFlux(String q,Long timeId) throws InterruptedException {
		System.out.println("开始调用大模型");

		TureList resultEntity =new TureList();
		List<AiPortAnswerList> aiPortAnswerLists=new ArrayList<>();
		//起3个Thread，去分别调用3个出题办法提升效率，最后返回合成一个结果
		Thread t1=new Thread(new Runnable() {
			@Override
			public void run() {
				aiPortAnswerLists.addAll(qrySingleQry(q).getAiPortAnswerLists());
				System.out.println("单选题完成");
			}
		});

		Thread t2=new Thread(new Runnable() {
			@Override
			public void run() {
				aiPortAnswerLists.addAll(qryNotSingleQry(q).getAiPortAnswerLists());
				System.out.println("多选题完成");
			}
		});

		Thread t3=new Thread(new Runnable() {
			@Override
			public void run() {
				aiPortAnswerLists.addAll(qrySelectQry(q).getAiPortAnswerLists());
				System.out.println("判断题完成");
			}
		});
		t1.start();
		t2.start();
		t3.start();
		//等待所有线程执行完毕
		t1.join();
		t2.join();
		t3.join();


		Long i=1L;
		for(AiPortAnswerList aiPortAnswerList:aiPortAnswerLists){
			aiPortAnswerList.getQuestion().setId(i++);
			Long j=1L;
			for(Answer answer:aiPortAnswerList.getAnswerList()){
				answer.setQuestionId(aiPortAnswerList.getQuestion().getId());
				answer.setId(j++);
			}
		}
			resultEntity.setAiPortAnswerLists(aiPortAnswerLists);
		System.out.println(resultEntity.toString());
		redisTemplate.opsForValue().set(timeId,resultEntity );
		return resultEntity;
	}

	public TureList qrySingleQry(String q) {
		// 限制输入文本长度，避免超出大模型限制
		String truncatedQ = q;
		if (q.length() > 129024) {
			truncatedQ = q.substring(0, 129024);
			System.out.println("输入文本过长，已截断至129024字符");
		}
		
		ChatClient chatClient = this.chatClientBuilder.defaultSystem("""
                你是专业企业机构的ai出题助手，帮助员工更好学习行业知识，聚焦于恒生电子的金融科技领域相关知识，
                能够智能化根据用户文本(文本是根据用户上传文件解析后的文字，请仔细甄别，可能解析出了一些不必要或者未知含义的文字，请不要受到影响)，
                根据该文本核心知识点生成题目,需要包含单选题，以及对应答案，15个单选题，部分题目选项需要有一定难度混淆答题者选择，
                并且需要对题目的难度打分(1-5)便于分类，然后以一定的格式返回给系统封装成实体返回。
                这是我的问题表的对应数据结构:
						public class Question implements java.io.Serializable{
						    /**
						    * 问题ID，主键自增
						    */
						    private Long id;
						                
						    /**
						    * 题目内容
						    */
						    private String content;
						                
						    /**
						    * 题目难度(1-5)
						    */
						    private Byte difficulty;
						                
						    /**
						    * 题目类型(1-单选)
						    */
						    private Byte type;
				这是我的答案表的对应数据结构:		            
						    public class Answer implements java.io.Serializable{
						          /**
						          * 答案ID，主键自增
						          */
						          private Long id;
						      
						          /**
						          * 关联的问题ID
						          */
						          private Long questionId;
						      
						          /**
						          * 答案文本
						          */
						          @Size(max = 500,message = "答案文本最大长度要小于 500")
						          private String content;
						      
						          /**
						          * 是否正确(1-正确 2-错误)
						          */
						          private Byte isCorrect;
						      
                ###回复格式样例

                **特别注意：**
                -分析过后严格按照格式返回
                """
		).build();
		TureList resultEntity = chatClient.prompt()
				.user(truncatedQ)
				.call()
				.entity(TureList.class);
		return resultEntity;
	}


	public TureList qryNotSingleQry(String q) {
		// 限制输入文本长度，避免超出大模型限制
		String truncatedQ = q;
		if (q.length() > 129024) {
			truncatedQ = q.substring(0, 129024);
			System.out.println("输入文本过长，已截断至129024字符");
		}
		
		ChatClient chatClient = this.chatClientBuilder.defaultSystem("""
                你是专业企业机构的ai出题助手，帮助员工更好学习行业知识，聚焦于恒生电子的金融科技领域相关知识，
                能够智能化根据用户文本(文本是根据用户上传文件解析后的文字，请仔细甄别，可能解析出了一些不必要或者未知含义的文字，请不要受到影响)，
                根据该文本核心知识点生成题目,需要包含单多选题，以及对应答案，15个多选题，每个多选题答案出6个，并且正确答案2个以上，并且每道题生成的答案要打乱顺序，部分题目选项需要有一定难度混淆答题者选择，
                并且需要对题目的难度打分(1-5)便于分类，然后以一定的格式返回给系统封装成实体返回。
                这是我的问题表的对应数据结构:
						public class Question implements java.io.Serializable{
						    /**
						    * 问题ID，主键自增
						    */
						    private Long id;
						                
						    /**
						    * 题目内容
						    */
						    private String content;
						                
						    /**
						    * 题目难度(1-5)
						    */
						    private Byte difficulty;
						                
						    /**
						    * 题目类型(2-多选 )
						    */
						    private Byte type;
				这是我的答案表的对应数据结构:		            
						    public class Answer implements java.io.Serializable{
						          /**
						          * 答案ID，主键自增
						          */
						          private Long id;
						      
						          /**
						          * 关联的问题ID
						          */
						          private Long questionId;
						      
						          /**
						          * 答案文本
						          */
						          @Size(max = 500,message = "答案文本最大长度要小于 500")
						          private String content;
						      
						          /**
						          * 是否正确(1-正确 2-错误)
						          */
						          private Byte isCorrect;
						      
                ###回复格式样例
               
                **特别注意：**
                -分析过后严格按照格式返回
                """
		).build();
		TureList resultEntity = chatClient.prompt()
				.user(truncatedQ)
				.call()
				.entity(TureList.class);
		return resultEntity;
	}

	public TureList qrySelectQry(String q) {
		// 限制输入文本长度，避免超出大模型限制
		String truncatedQ = q;
		if (q.length() > 129024) {
			truncatedQ = q.substring(0, 129024);
			System.out.println("输入文本过长，已截断至129024字符");
		}
		
		ChatClient chatClient = this.chatClientBuilder.defaultSystem("""
                你是专业企业机构的ai出题助手，帮助员工更好学习行业知识，聚焦于恒生电子的金融科技领域相关知识，
                能够智能化根据用户文本(文本是根据用户上传文件解析后的文字，请仔细甄别，可能解析出了一些不必要或者未知含义的文字，请不要受到影响)，
                根据该文本核心知识点生成题目,需要包含判断题，以及对应答案，需要10个判断题，判断选项的答案1对1错，并且每道题生成的答案要打乱顺序，部分题目选项需要有一定难度混淆答题者选择，
                并且需要对题目的难度打分(1-5)便于分类，然后以一定的格式返回给系统封装成实体返回。
                这是我的问题表的对应数据结构:
						public class Question implements java.io.Serializable{
						    /**
						    * 问题ID，主键自增
						    */
						    private Long id;
						                
						    /**
						    * 题目内容
						    */
						    private String content;
						                
						    /**
						    * 题目难度(1-5)
						    */
						    private Byte difficulty;
						                
						    /**
						    * 题目类型(3-判断)
						    */
						    private Byte type;
				这是我的答案表的对应数据结构:		            
						    public class Answer implements java.io.Serializable{
						          /**
						          * 答案ID，主键自增
						          */
						          private Long id;
						      
						          /**
						          * 关联的问题ID
						          */
						          private Long questionId;
						      
						          /**
						          * 答案文本
						          */
						          @Size(max = 500,message = "答案文本最大长度要小于 500")
						          private String content;
						      
						          /**
						          * 是否正确(1-正确 2-错误)
						          */
						          private Byte isCorrect;
						      
                ###回复格式样例
    
                
                **特别注意：**
                -分析过后严格按照格式返回
                """
		).build();
		TureList resultEntity = chatClient.prompt()
				.user(truncatedQ)
				.call()
				.entity(TureList.class);
		return resultEntity;
	}











	@PostMapping("/getAiQuestion")
	public TureList uploadFile(Long timeId) {

		TureList resultEntity = (TureList)redisTemplate.opsForValue().get(timeId);
		if(resultEntity==null){
			return null;
		}
		return resultEntity;
	}

	@PostMapping("saveAiQuestion/{timeId}")
	public ResponseEntity saveAiQuestion(@RequestBody TureList resultEntity,@PathVariable Long timeId) {
		System.out.println(resultEntity);
		System.out.println(timeId);
		redisTemplate.opsForValue().set(timeId, resultEntity);
		return ResponseEntity.ok("保存成功");
	}

}



